package samples.examples.bezier_chain.application ;

import divtastic.js.DisplayDiv ;
import divtastic.js.Drawing;
import divtastic.js.application.views.WindowView ;
import haxe.Timer;
import js.Dom ;
import feffects.Tween;
import divtastic.Movement;

using divtastic.js.Drawing;
class Controller
{
    
    
    private var _holder:                DisplayDiv;
    private var _lineHolder:            DisplayDiv;
    private var circleRed:              DisplayDiv;
    private var circleGreen:            DisplayDiv;
    private var circleBlue:             DisplayDiv;
    private var circleMauve:            DisplayDiv;
    private var circleCyan:             DisplayDiv;
    private var circleOrange:           DisplayDiv;
    private var circleYellow:           DisplayDiv;
    
    private static inline var red:      Int         = 0xff0000;
    private static inline var green:    Int         = 0x00ff00;
    private static inline var blue:     Int         = 0x0000ff;
    private static inline var yellow:   Int         = 0xffff00;
    private static inline var mauve:    Int         = 0xff00ff;
    private static inline var cyan:     Int         = 0x00ffff;
    private static inline var orange:   Int         = 0xff6600;
    private static inline var greyC:    Int         = 0xcccccc;
    private static inline var grey6:    Int         = 0x666666;
    private static inline var diaX:     Int         = 18;
    private static inline var diaY:     Int         = 20;
    private static inline var velocity: Int         = 2500;
    private var points:                 List<Array<Float>>;
    private var circles:                Array<DisplayDiv>;
    private var clearPoints:            List<List<HtmlDom>>;
    private var greyCircles:            Array<DisplayDiv>;
    private var greyCircleNum:          Int;
    private var _reRender:              DisplayDiv;
    
    public function new( holder_: DisplayDiv )
    {
        clearPoints             = new List();
        _holder                 = holder_ ;
        _lineHolder             = new DisplayDiv();
        _lineHolder.x           = 0;
        _lineHolder.y           = 0;
        
        _holder.addChild( _lineHolder );
        
        // Note you can add this button and remove the dragging listening if too heavy.
        //createRenderButton();
        
        circleRed               = createCircle( 20, 200, red ) ;
        circleRed.setupDrag();
        
        circleRed.dragging.add( renderLines );
        circleRed.dragInform = true;
        circleRed.release.add( renderLines );
        
        circleGreen             = createCircle( 200, 30, green ) ;
        circleGreen.setupDrag();
        
        circleGreen.dragging.add( renderLines );
        circleGreen.dragInform = true;
        
        circleGreen.release.add( renderLines );
        
        circleBlue              = createCircle( 450, 350, blue );
        circleBlue.setupDrag();
        circleBlue.dragging.add( renderLines );
        circleBlue.dragInform = true;
        circleBlue.release.add( renderLines );
        
        circleMauve             = createCircle( 60, 150, mauve );
        circleMauve.setupDrag();
        circleMauve.dragging.add( renderLines );
        circleMauve.dragInform = true;
        
        circleMauve.release.add( renderLines );
        
        circleCyan              = createCircle( 90, 400, cyan );
        circleCyan.setupDrag();
        circleCyan.dragging.add( renderLines );
        circleCyan.dragInform = true;
        
        circleCyan.release.add( renderLines );
        
        circleOrange            = createCircle( 300, 90, orange );
        circleOrange.setupDrag();
        
        circleOrange.dragging.add( renderLines );
        
        circleOrange.dragInform = true;        circleRed.dragging.add( renderLines );
        circleOrange.dragInform = true;
        circleOrange.release.add( renderLines );
        
        circleOrange.release.add( renderLines );
        
        circleYellow            = createCircle( 20, 200, yellow );
        
        
        circleYellow.visible    = false;
        createRightArrow( _holder );
        
        
        circles =   [   circleRed
                    ,   circleGreen
                    ,   circleBlue
                    ,   circleCyan
                    ,   circleMauve
                    ,   circleOrange
                    ];
        
        greyCircles = new Array();
        greyCircleNum = 0;
        //TODO: change so don't double up on grey circles.
        for( i in 0...(2*(circles.length-2)) )
        {
            
            greyCircles.push( createCircle( Std.int( 0 ), Std.int( 0 ), grey6 ));
            
        }
        
        renderLines();
        
    }
    
    public function createRenderButton()
    {
        
        _reRender               = new DisplayDiv();
        _reRender.x             = 5;
        _reRender.y             = 35;
        _reRender.text          = ' RE CALCULATE ';
        _reRender.fill          = '#999999';
        var txStyle             = _reRender.getStyle();
        txStyle.cursor          = 'pointer';
        txStyle.fontFamily      = 'Monaco';
        txStyle.color           = '#ffffff';
        txStyle.lineHeight      = '1.3';
        txStyle.letterSpacing   = '1px';
        txStyle.fontSize        = '20';
        
        _holder.addChild( _reRender );
        _reRender.press.add( renderLines );
        
    }
    
    
    public function renderLines()
    {
        
        drawConstructions();
        points = generatePoints( circles );
        
    }
    
    
    public function generatePoints( arr: Array<DisplayDiv> ): List<Array<Float>>
    {
        
        var xs: Array<Float> = [];
        var ys: Array<Float> = [];
        var a:  DisplayDiv;
        var b:  DisplayDiv;
        
        for( i in 0...(arr.length - 1) )
        {
            
            a = arr[ i ];
            b = arr[ i + 1 ];
            xs.push( ( b.x + a.x )/2 );
            xs.push( b.x );
            ys.push( ( b.y + a.y )/2 );
            ys.push( b.y );
            
        }
        
        xs.pop();
        ys.pop();
        var l = new List();
        l.add( xs );
        l.add( ys );
        return l;
        
    }
    
    
    public function drawConstructions()
    {
        // destroy old constructions.
        if( clearPoints != null )
        {
            
            for( i in clearPoints )
            {
                
                for( j in i )
                {
                    
                    _lineHolder.getInstance().removeChild( j );
                    
                }
                
                i = null;
                
            }
            
        }
        
        greyCircleNum   = 0;
        var temp        = new List();
        
        temp.add( joinLine( circleRed, circleGreen ) );
        temp.add( joinLine( circleGreen, circleBlue ) );
        temp.add( joinCurve( circleRed, circleGreen, circleBlue ) );
        temp.add( joinLine( circleBlue, circleCyan ) );
        temp.add( joinCurve( circleGreen, circleBlue, circleCyan ) );
        temp.add( joinLine( circleCyan, circleMauve ) );
        temp.add( joinCurve( circleBlue, circleCyan, circleMauve ) );
        temp.add( joinLine( circleMauve, circleOrange ) );
        temp.add( joinCurve( circleCyan, circleMauve, circleOrange ) );
        
        clearPoints = temp;
        
    }
    
    
    public function joinLine( circleA: DisplayDiv, circleB: DisplayDiv ): List<HtmlDom>
    {
        
        return _lineHolder.lineFromTo   (    circleA.x + diaX/2
                                        ,   circleA.y + diaY/2
                                        ,   circleB.x + diaX/2
                                        ,   circleB.y + diaY/2
                                        , 3, 3, '#333333'
                                        );
        
    }
    
    
    public function joinCurve   (   circleA: DisplayDiv
                                ,   circleB: DisplayDiv
                                ,   circleC: DisplayDiv
                                ): List<HtmlDom>
    {
        
        var ax = ( circleB.x + circleA.x )/2;
        var ay = ( circleB.y + circleA.y )/2;
        //createCircle( Std.int( ax ), Std.int( ay ), grey6 );
        
        var circ = greyCircles[ greyCircleNum ];
        greyCircleNum++;
        
        circ.x = ax;
        circ.y = ay;
        
        
        var cx = ( circleC.x + circleB.x )/2;
        var cy = ( circleC.y + circleB.y )/2;
        //createCircle( Std.int( cx ), Std.int( cy ), grey6 );
        
        circ = greyCircles[ greyCircleNum ];
        
        greyCircleNum++;
        
        circ.x = cx;
        circ.y = cy;
        
        return _lineHolder.curveFromTo  (   ax + diaX/2,            ay + diaY/2
                                        ,   circleB.x + diaX/2,     circleB.y + diaY/2
                                        ,   cx + diaX/2,            cy+ diaY/2
                                        ,   2, 2, '#666666' );
        
    }
    
    
    private function createCircle( x: Int, y: Int, col: Int ): DisplayDiv
    {
        
        var circle      = new DisplayDiv() ;
        circle.x        = x;
        circle.y        = y;
        var divs        = circle.drawGradElipse( 0, 0, diaX, diaY, col, col );
        _holder.addChild( circle );
        return circle;
        
    }
    
    private function createRightArrow( aTab: DisplayDiv ): HtmlDom
    {
        
        var right       = new DisplayDiv();
        right.x         = 5;
        right.y         = 0;
        aTab.addChild( right );
        var grey6       = 0x666666;
        var grey36      = 0x363636;
        right.drawGradTriangle( 4, 4, 24, 30, grey36, grey6, West, 1, Horizontal );
        right.getStyle().cursor = 'pointer';
        right.press.add( move ) ;
        return right.getInstance() ;
        
    }
    
    public function move()
    {
        
        circleYellow.x          = circleRed.x;
        circleYellow.y          = circleRed.y;
        circleYellow.visible    = true ;
        var numBeziers          = circles.length - 2;
        var t                   = new Tween( 0, 1, velocity );
        var xs                  = points.first();
        var ys                  = points.last();
        
        t.setTweenHandlers( function( e ){
                                                var mult    = e*numBeziers;
                                                var section = Math.floor( mult );
                                                var j       = Std.int( section*2 );
                                                var new_e   = mult - section;
                                                
                                                circleYellow.x = Movement.quadraticBezier( new_e
                                                                                    , xs[ j ]
                                                                                    , xs[ j + 1 ]
                                                                                    , xs[ j + 2 ]
                                                                                    );
                                                circleYellow.y = Movement.quadraticBezier( new_e
                                                                                    , ys[ j ]
                                                                                    , ys[ j + 1 ]
                                                                                    , ys[ j + 2 ]
                                                                                    ); 
                                                
                                                }
                            , function( e ){
                                                circleYellow.visible = false ;
                                            }
                            );
        t.start();
        
    }
    
    
}
